home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / prog / pas_all.zip / TI174.ASC < prev    next >
Text File  |  1991-09-11  |  19KB  |  595 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.   PRODUCT  :  Turbo Pascal                           NUMBER  :  174
  9.   VERSION  :  3.01A
  10.        OS  :  PC DOS
  11.      DATE  :  August 1, 1986                           PAGE  :  1/9
  12.  
  13.     TITLE  :  Files Open Extend
  14.  
  15.  
  16.  
  17.  
  18.   The following is public domain information that has been uploaded
  19.   to our Forum on CompuServe. As a courtesy to our users that do
  20.   not have immediate access to CompuServe, Technical Support
  21.   distributes these routines free of charge.
  22.  
  23.   However, because these routines are public domain programs, not
  24.   developed by Borland International, we are unable to provide any
  25.   technical support or assistance using these routines. If you need
  26.   assistance using these routines, or are experiencing
  27.   difficulties, we recommend that you log onto CompuServe and
  28.   request assistance from the Forum members that developed these
  29.   routines.
  30.  
  31.   Written by:
  32.   Randy Forgaard, CompuServe 70307,521
  33.   Many thanks to Bela Lubkin (CompuServe 76703,3015) for
  34.   masterminding this idea, and Kim Kokkonen (CompuServe 72457,2131)
  35.   for helping me debug it. For more discussion of Handle Tables and
  36.   the implementation of DOS redirection, please see Stan Mitchell,
  37.   "Command Line Redirection," PC Tech Journal, January 1986, Page
  38.   44.
  39.  
  40.   Due to a limitation of DOS, Turbo Pascal version 3.0 only allows
  41.   up to 15 files at a time to be open. The following method allows
  42.   you to have up to 96 files open simultaneously under DOS 2.0 or
  43.   2.1, or 252 files open simultaneously under DOS 3.0 or greater.
  44.  
  45.   TO USE THIS TECHNIQUE:
  46.  
  47.   You need the routines and global declarations below. Everywhere
  48.   in your program that you Reset or Rewrite a file "f" for the
  49.   first time, insert an "OpenExtend(f);" invocation immediately
  50.   after the Reset or Rewrite. Each time your program calls one of
  51.   Turbo's built-in routines (other than Assign) for handling files
  52.   (e.g., Read, Write, Close, Seek, Reset, Rewrite, etc.), put an
  53.   "UnExtend(f);" invocation immediately prior to the call, and a
  54.   "ReExtend(f);" invocation immediately after the call. Do not
  55.   insert UnExtend and ReExtend calls around the very first Reset or
  56.   Rewrite that you use to initially open a file.
  57.  
  58.   At the top of your program, prior to the "program" statement, put
  59.   the compiler directive {$F252}. (You may use a value smaller than
  60.   252 if you wish. Under DOS 2.0/2.1, values above 96 have
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.   PRODUCT  :  Turbo Pascal                           NUMBER  :  174
  75.   VERSION  :  3.01A
  76.        OS  :  PC DOS
  77.      DATE  :  August 1, 1986                           PAGE  :  2/9
  78.  
  79.     TITLE  :  Files Open Extend
  80.  
  81.  
  82.  
  83.  
  84.   no additional benefit. Each larger value for the {$F} directive
  85.   uses 2 additional bytes in the program's global data space.) The
  86.   value you specify for the {$F} directive is the maximum number of
  87.   files you will be able to have open at the same time in your
  88.   program.
  89.  
  90.   Edit your CONFIG.SYS file (see the DOS manual for details) so
  91.   that it includes a line that says "FILES=XXX". XXX should be a
  92.   number that is 3 greater than the value you specified for the
  93.   {$F} directive (larger values will provide no additional benefit
  94.   with respect to your individual program), and should not exceed
  95.   99 (for DOS 2.0/2.1) or 255 (for DOS 3.0 and higher). Under any
  96.   version of DOS, the minimum allowable value for XXX is 8. Then,
  97.   reboot your computer so that the FILES=XXX parameter takes hold.
  98.   Running the sample program at the bottom of this file will tell
  99.   you the maximum number of files you can open at once. (Usually 96
  100.   or 252, unless a resident program has opened some files and
  101.   hasn't closed them yet.)
  102.  
  103.   THE TECHNICAL DETAILS:
  104.  
  105.   Much of the following information is not documented in the DOS
  106.   Technical Reference manual.
  107.  
  108.   Under DOS 1.0 and 1.1, all files were accessed via File Control
  109.   Blocks (FCB's). There was no limit to the number of FCB's that a
  110.   program could use, so there was no limit to the number of files
  111.   open simultaneously.
  112.  
  113.   Under DOS 2.0 and greater, an alternate (and preferable) method
  114.   of accessing files was introduced which uses a 2-byte integer
  115.   called a "handle" to refer to a file. A "handle" file is
  116.   described using a data structure called a Device Control Block
  117.   (DCB). However, DOS provides the storage space for all DCB's,
  118.   rather than having the application program store the DCB's, so
  119.   the number of available DCB's is limited to the amount of space
  120.   that DOS has set aside for them. The maximum number of
  121.   files/devices that can be open simultaneously is the number of
  122.   slots available in the DCB Table created by DOS. The DCB's in the
  123.   DCB Table are consecutively numbered, starting with 0. DCB's 0,
  124.   1, and 2 are predefined by DOS to correspond to the AUX, CON, and
  125.   PRN devices, respectively. All remaining DCB's in the DCB Table
  126.   are available for files or devices used by application programs.
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.   PRODUCT  :  Turbo Pascal                           NUMBER  :  174
  141.   VERSION  :  3.01A
  142.        OS  :  PC DOS
  143.      DATE  :  August 1, 1986                           PAGE  :  3/9
  144.  
  145.     TITLE  :  Files Open Extend
  146.  
  147.  
  148.  
  149.  
  150.   So that I/O redirection can be supported, the DCB numbers are not
  151.   used directly when accessing files. Instead, a file "handle" is
  152.   used. A "handle" is an index into a 20-byte array, called the
  153.   Handle Table, which is located at offset 18H of the Program
  154.   Segment Prefix (PSP) for a program (for a general discussion of
  155.   the PSP, see the DOS Technical Reference manual). Each element of
  156.   the Handle Table is the DCB number of a file or device. The value
  157.   at index "handle" in the Handle Table is the DCB number of the
  158.   file or device that implements that file handle. Thus, if the
  159.   value 8 is in the 6th byte of the Handle Table, the handle "6"
  160.   refers to the file (or device) described by the DCB in slot 8 of
  161.   the DCB Table. If a handle is not currently being used, its entry
  162.   in the Handle Table is FFH. DOS predefines the first 5 handles to
  163.   be primary input, primary output, error, auxiliary, and printer,
  164.   so the first 5 entries in the Handle Table are 1, 1, 1, 0, and 2,
  165.   corresponding to the DCB numbers for the CON (1), AUX (0), and
  166.   PRN (2) devices. This leaves only 15 available handles for
  167.   opening files (or new devices).
  168.  
  169.   Every time a new handle file is opened, a new handle gets used.
  170.   Since there are only 20 slots available in the Handle Table for a
  171.   program, DOS only allows a "process" to have a maximum of 20 file
  172.   handles in use simultaneously (and the first 5 entries are
  173.   predefined, as just noted, unless those handles get closed and
  174.   reused). Every new handle file requires a unique handle, so only
  175.   20 files/devices can be open at the same time by a single process
  176.   (unless FCB's are used). (A "process" is any program spawned
  177.   using the DOS EXEC function call. A process can be invoked by
  178.   COMMAND.COM, or by another program.) There can be many more than
  179.   20 DCB's in the DCB Table, so the real limitation is in the size
  180.   of the Handle Table in the PSP.
  181.  
  182.   The size of the DCB Table (i.e., the maximum number of
  183.   files/devices that can be open simultaneously in the whole
  184.   computer) is controlled by the FILES=XXX entry in the CONFIG.SYS
  185.   file. The minimum number of slots is 8. Under DOS 2.0/2.1, the
  186.   maximum number is 99, and under DOS 3.0 and higher, the maximum
  187.   is 255. As previously mentioned, the first three of these DCB
  188.   slots are occupied by the AUX, CON, and PRN devices.
  189.  
  190.   A single program can use all of the DCB's in the DCB Table
  191.   (except for the 3 reserved by DOS) all on its own, by effectively
  192.   bypassing the Handle Table in the PSP, except on a temporary
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.   PRODUCT  :  Turbo Pascal                           NUMBER  :  174
  207.   VERSION  :  3.01A
  208.        OS  :  PC DOS
  209.      DATE  :  August 1, 1986                           PAGE  :  4/9
  210.  
  211.     TITLE  :  Files Open Extend
  212.  
  213.  
  214.  
  215.  
  216.   basis. The program can accomplish this feat by using, say, only
  217.   one entry in the Handle Table for all of its files. Instead of
  218.   allowing DOS to store the DCB numbers in the Handle Table, the
  219.   program can store these numbers elsewhere. Then, to manipulate a
  220.   file using DOS, the program can temporarily put the DCB number of
  221.   that file into a designated slot in the Handle Table, pass the
  222.   index of that table slot (i.e., that "handle") to DOS, and DOS
  223.   will operate on that handle/DCB number. After the DOS call, the
  224.   program can remove that DCB number from the designated Handle
  225.   Table slot, freeing up that handle for use in another DOS call
  226.   for another file. In this way, DOS can be fooled into accessing
  227.   up to 96 (or 252) different files/devices using a single handle
  228.   entry in the Handle Table.
  229.  
  230.   The OpenExtend, UnExtend, and ReExtend routines below use this
  231.   technique. OpenExtend(f) is used on a previously-opened file,
  232.   "f." It removes f's DCB number from the Handle Table, and stores
  233.   that DCB number in place of the file handle in Turbo's data
  234.   structure for "f." UnExtend(f) copies the current DCB number (if
  235.   any) in the last slot of the Handle Table to a safe place, copies
  236.   the DCB number of "f" to that slot, and then puts the handle of
  237.   that slot into the "handle" position of the data structure for
  238.   "f," in preparation for its use by Turbo/DOS. ReExtend(f)
  239.   replaces the file handle of "f" with the DCB number for "f" in
  240.   the data structure for "f," and restores the previous value (if
  241.   any) of the last slot in the Handle Table. Note that the last
  242.   slot of the Handle Table was chosen totally arbitrarily. Any  H
  243.   Table entry can be used for fooling DOS, and (since we are saving
  244.   the previous DCB number in that entry) it does not preclude also
  245.   using that designated slot as a legitimate handle.
  246.  
  247.   To obtain the address of the Handle Table, which is at offset 18H
  248.   in the PSP, the program needs to find the address of its PSP.
  249.   Normally, this is very easy: when DOS loads a .COM file, the
  250.   address of the PSP is just CS:0000. Using CS:0000 in this manner
  251.   would be viable as long as we compile the program to a .COM file
  252.   and execute the .COM file. However, if we run the program in
  253.   DOS, it still thinks of Turbo's PSP as being the "official" PSP
  254.   for  the running program, since DOS did not "see" Turbo invoke
  255.   the program. Hence, CS:0000 is not the valid PSP address when the
  256.   program is running in memory, since that is the address of the
  257.   program's "fake" PSP rather than Turbo's PSP.
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.   PRODUCT  :  Turbo Pascal                           NUMBER  :  174
  273.   VERSION  :  3.01A
  274.        OS  :  PC DOS
  275.      DATE  :  August 1, 1986                           PAGE  :  5/9
  276.  
  277.     TITLE  :  Files Open Extend
  278.  
  279.  
  280.  
  281.  
  282.   To allow the program to work correctly both when running in
  283.   memory and when run as a .COM file, we use the DOS function call
  284.   62H, "Get Program Segment Prefix Address (PSP)." This function
  285.   call is available in DOS 3.0 and higher. There is an identical
  286.   function call in DOS 2.0/2.1, but its function number is 51H, and
  287.   it is not documented. Function 51H is also available in DOS
  288.   3.0/3.1. However, for upward-compatibility reasons with future
  289.   versions of DOS, we will use the undocumented 51H function with
  290.   DOS 2.0/2.1 (since we know 51H is available in those versions of
  291.   DOS), and use 62H for DOS 3.0 and higher (since 62H is a
  292.   documented function). There is no such function call in DOS
  293.   1.0/1.1, but the technique below will not work with those early
  294.   versions of DOS anyway, since they did not provide file handles.
  295.   To decide whether to use function 51H or 62H, we call DOS
  296.   function 30H, "Get DOS Version Number," to determine which
  297.   version of DOS is running. This strategy for obtaining the Handle
  298.   Table address is implemented in the GetHandleTableAddr function,
  299.   below, which gets called only once (the first time that
  300.   OpenExtend is called).
  301.  
  302.   Note: This technique will not interfere with overlays in your
  303.   program (since it only uses the Handle Table slot temporarily),
  304.   provided that your program leaves at least one DCB available for
  305.   use by the Turbo run-time library to read in overlay files.
  306.  
  307.   {$F252}
  308.  
  309.   const
  310.     LastHandle = 19;    {Highest-numbered handle}
  311.     UnusedHandle = $FF; {DcbTable entry that denotes an unused
  312.   handle}
  313.   type
  314.     HandleTable = array[0..LastHandle] of Byte;
  315.     HandleTablePtr = ^HandleTable;
  316.   const
  317.     TablePtrOk: Boolean = false; {"True" iff TablePtr is
  318.   initialized}
  319.   var
  320.     TablePtr: HandleTablePtr; {Points to Handle Table for this
  321.   process}
  322.     SaveDcb:  Byte;  {Temporary variable for a DCB number during a
  323.   function
  324.                                   call}
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.   PRODUCT  :  Turbo Pascal                           NUMBER  :  174
  339.   VERSION  :  3.01A
  340.        OS  :  PC DOS
  341.      DATE  :  August 1, 1986                           PAGE  :  6/9
  342.  
  343.     TITLE  :  Files Open Extend
  344.  
  345.  
  346.  
  347.  
  348.   {Internal  routine.   Returns  the address of the  Handle  Table,
  349.   which is at offset 18H in the PSP.}
  350.  
  351.   function GetHandleTableAddr: HandleTablePtr;
  352.   var
  353.     regs: record
  354.                   case Integer of
  355.                     1: (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags:
  356.   Integer);
  357.                     2: (AL, AH, BL, BH, CL, CH, DL, DH: Byte)
  358.                   end;
  359.  
  360.   begin
  361.     regs.AH := $30;
  362.     MsDos(regs);      {Get DOS version number}
  363.     case regs.AL of
  364.       0: begin
  365.                   writeln('This program only works with DOS 2.0 and
  366.   higher');
  367.                   Halt
  368.             end;
  369.       2: regs.AH := $51; {Undocumented, but works with DOS 2.0/2.1
  370.   (and 3.X)}
  371.     else regs.AH := $62  {Works with DOS 3.0 and higher}
  372.     end;
  373.     MsDos(regs);      {Get PSP address}
  374.     GetHandleTableAddr := Ptr(regs.BX, $18)
  375.   end {GetHandleTableAddr};
  376.  
  377.  
  378.   {Causes "f" to become an "extended" file; i.e., to remain open
  379.   without using up any file handles. The parameter "f" must be any
  380.   Turbo file;  e.g., a File, a File of Byte, a File of Foo, Text,
  381.   etc. This routine should be called immediately after the Reset or
  382.   Rewrite that is initially used to open "f." After "f" has become
  383.   extended, it cannot be used by Turbo's built-in file routines
  384.   until it has been unextended using UnExtend.}
  385.  
  386.   procedure OpenExtend (var f);
  387.   var
  388.     handle: Integer absolute f;
  389.   begin
  390.     if not TablePtrOk then
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.   PRODUCT  :  Turbo Pascal                           NUMBER  :  174
  405.   VERSION  :  3.01A
  406.        OS  :  PC DOS
  407.      DATE  :  August 1, 1986                           PAGE  :  7/9
  408.  
  409.     TITLE  :  Files Open Extend
  410.  
  411.  
  412.  
  413.  
  414.       begin
  415.            TablePtr := GetHandleTableAddr;
  416.            TablePtrOk := true
  417.       end;
  418.     SaveDcb := TablePtr^[handle];
  419.     TablePtr^[handle] := UnusedHandle;
  420.     handle := SaveDcb
  421.   end {OpenExtend};
  422.  
  423.  
  424.   {Unextends the extended file "f," so that it can be used by any
  425.   of Turbo's built-in file routines. Note that "f" must have been
  426.   converted  to an extended file by OpenExtend before invoking
  427.   UnExtend(f). After calling UnExtend, and then invoking the Turbo
  428.   file function on "f," ReExtend(f) should be invoked immediately
  429.   to re-extend "f" and restore the DOS file state information.}
  430.  
  431.   procedure UnExtend (var f);
  432.   var
  433.     handle: Integer absolute f;
  434.   begin
  435.     SaveDcb := TablePtr^[LastHandle];
  436.     TablePtr^[LastHandle] := Lo(handle);
  437.     handle := LastHandle
  438.   end {UnExtend};
  439.  
  440.  
  441.   {Re-extends "f" into an extended file. Note that "f" must have
  442.   been converted to an extended file by OpenExtend, and then
  443.   unextended  using UnExtend, before "f" can re-extended using
  444.   ReExtend.  ReExtend(f) should be invoked immediately after any
  445.   normal Turbo file function call using "f."}
  446.  
  447.   procedure ReExtend (var f);
  448.   var
  449.     handle: Integer absolute f;
  450.   begin
  451.     handle := TablePtr^[LastHandle];
  452.     TablePtr^[LastHandle] := SaveDcb
  453.   end {ReExtend};
  454.  
  455.   {Example program -- This program opens as many Text files as it
  456.   can,  until DOS runs out of room in its DCB Table. It then
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.   PRODUCT  :  Turbo Pascal                           NUMBER  :  174
  471.   VERSION  :  3.01A
  472.        OS  :  PC DOS
  473.      DATE  :  August 1, 1986                           PAGE  :  8/9
  474.  
  475.     TITLE  :  Files Open Extend
  476.  
  477.  
  478.  
  479.  
  480.   reports how many files were successfully opened, writes a line to
  481.   each of them, then closes and erases each of them. Note: The
  482.   value of the FILES=XXX parameter in the CONFIG.SYS file must be
  483.   set to an appropriate value (see above). If you change the
  484.   FILES=XXX value, be sure to reboot before running this program.
  485.  
  486.   This program takes a while to run, due to the heavy disk I/O, so
  487.   running it on a hard disk (or, even better, a RAM disk) is
  488.   recommended.  Make sure that you are running the program in a
  489.   subdirectory, so that you don't run up against the DOS limit on
  490.   the number of allowable files in the root directory of a drive.}
  491.  
  492.   const
  493.     MaxCount = 255;
  494.   var
  495.     num: string[6];
  496.     f: array[1..MaxCount] of Text;
  497.     i, count: Integer;
  498.     result: Byte;
  499.   begin
  500.     writeln('Opening files...');
  501.     i := 0;
  502.     repeat
  503.       i := i + 1;
  504.       Str(i, num);
  505.       Assign(f[i], 'junk' + num + '.txt');
  506.       {$I-} Rewrite(f[i]); {$I+}
  507.       result := IOResult;
  508.       if result = 0 then OpenExtend(f[i])
  509.     until result <> 0;
  510.     count := i - 1;
  511.     writeln('Successfully opened ', count, ' files at the same
  512.   time.  ',
  513.                   'Writing to each file...');
  514.     for i := 1 to count do
  515.       begin
  516.            UnExtend(f[i]);
  517.            writeln(f[i], 'This is a test');
  518.            ReExtend(f[i])
  519.       end;
  520.     writeln('Closing and erasing each file...');
  521.     for i := 1 to count do
  522.       begin
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536.   PRODUCT  :  Turbo Pascal                           NUMBER  :  174
  537.   VERSION  :  3.01A
  538.        OS  :  PC DOS
  539.      DATE  :  August 1, 1986                           PAGE  :  9/9
  540.  
  541.     TITLE  :  Files Open Extend
  542.  
  543.  
  544.  
  545.  
  546.            UnExtend(f[i]);
  547.            Close(f[i]);
  548.            Erase(f[i]);
  549.            ReExtend(f[i])
  550.       end;
  551.     writeln('Done.')
  552.   end.
  553.   (**)
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577.  
  578.  
  579.  
  580.  
  581.  
  582.  
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595.